import { Definition, DefinitionLink } from "vscode-languageserver";
import { pathToUri } from "./translation";
import { getNodeWithPathAtPosition } from "./util";
import { t } from "./analysis";

export async function provideDefinition(source: t.SourceFile, position: number): Promise<Definition | DefinitionLink[] | null> {
    let nodeResult = getNodeWithPathAtPosition(source, position);
    let symbol = nodeResult.node?.symbol;
    let declaration = symbol?.declaration;

    if (!nodeResult.node || !symbol || !declaration || declaration.isMissingNode()) {
        return null;
    }

    if (declaration.isSourceFile()) {
        return [{
            originSelectionRange: {
                start: source.getLineAndCharactorOfPosition(nodeResult.node.start),
                end: source.getLineAndCharactorOfPosition(nodeResult.node.end)
            },
            targetUri: pathToUri(declaration.fileName),
            targetRange: {
                start: declaration.getLineAndCharactorOfPosition(declaration.start),
                end: declaration.getLineAndCharactorOfPosition(declaration.end)
            },
            targetSelectionRange: {
                start: declaration.getLineAndCharactorOfPosition(0),
                end: declaration.getLineAndCharactorOfPosition(0),
            }
        }];
    }

    // module 声明允许在多个文件中重复声明
    if (symbol.is(t.SymbolKind.module)) {
        let links: DefinitionLink[] = [];
        symbol.tracker.forEachNode(node => {
            if (node.parent?.isSignature<t.ModuleSignature>(t.SyntaxKind.moduleSignature)) {
                let file = node.getSourceFile();
                if (file) {
                    links.push({
                        targetUri: pathToUri(file.fileName),
                        targetRange: {
                            start: file.getLineAndCharactorOfPosition(node.parent.start),
                            end: file.getLineAndCharactorOfPosition(node.parent.end)
                        },
                        targetSelectionRange: {
                            start: file.getLineAndCharactorOfPosition(node.start),
                            end: file.getLineAndCharactorOfPosition(node.end)
                        }
                    });
                }
            }
        });
        return links;
    }

    let declarationFile = declaration.getSourceFile();
    if (!declarationFile) {
        return null;
    }

    return {
        uri: pathToUri(declarationFile.fileName),
        range: {
            start: declarationFile.getLineAndCharactorOfPosition(declaration.start),
            end: declarationFile.getLineAndCharactorOfPosition(declaration.end)
        }
    };
}
